#include <bits/stdc++.h>
using namespace std;

// 常量
const int MAX_M = 20, MAX_N = 20;

// 输入数据
int m, n;                                       // 机器数和工件数
vector<int> order;                              // 操作顺序
int machine[MAX_N][MAX_M];                      // 工件 j 的工序 k 使用的机器
int time_cost[MAX_N][MAX_M];                    // 工件 j 的工序 k 的加工时间
vector<pair<int, int>> machine_schedule[MAX_M]; // 每台机器的调度（开始时间，结束时间）
int job_finish_time[MAX_N];                     // 每个工件最后操作的完成时间
int job_progress[MAX_N];                        // 每个工件的当前工序索引

// 查找机器上最早可用的时间段
int find_earliest_slot(int mach, int duration, int earliest_start)
{
    // 如果机器空闲，直接从 earliest_start 开始
    if (machine_schedule[mach].empty())
    {
        return earliest_start;
    }

    // 检查间隙
    int start = earliest_start;
    for (int i = 0; i <= machine_schedule[mach].size(); i++)
    {
        int gap_start = (i == 0) ? 0 : machine_schedule[mach][i - 1].second;
        int gap_end = (i == machine_schedule[mach].size()) ? INT_MAX : machine_schedule[mach][i].first;
        if (gap_start >= earliest_start && gap_start + duration <= gap_end)
        {
            // 如果间隙足够大且满足最早开始时间
            return gap_start;
        }
        else if (gap_start < earliest_start && earliest_start + duration <= gap_end)
        {
            // 如果间隙开始时间早于 earliest_start，但从 earliest_start 开始可行
            return earliest_start;
        }
        start = max(start, machine_schedule[mach][i - 1].second);
    }
    return start;
}

int main()
{
    // 读取输入
    cin >> m >> n;
    order.resize(m * n);
    for (int i = 0; i < m * n; i++)
    {
        cin >> order[i];
        order[i]--; // 转换为 0 基索引
    }

    // 读取机器分配
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> machine[i][j];
            machine[i][j]--; // 转换为 0 基索引
        }
    }

    // 读取加工时间
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> time_cost[i][j];
        }
    }

    // 初始化
    memset(job_progress, 0, sizeof(job_progress));
    memset(job_finish_time, 0, sizeof(job_finish_time));

    // 按给定顺序处理操作

    for (int i = 0; i < m * n; i++)
    {
        int job = order[i];                        // 当前工件
        int op = job_progress[job];                // 当前工序索引
        int mach = machine[job][op];               // 该工序的机器
        int duration = time_cost[job][op];         // 加工时间
        int earliest_start = job_finish_time[job]; // 最早开始时间（在上一个工序之后）

        // 找到最早可用的时间段
        int start_time = find_earliest_slot(mach, duration, earliest_start);

        // 调度操作
        machine_schedule[mach].push_back({start_time, start_time + duration});
        // 按开始时间排序以便后续查找间隙
        sort(machine_schedule[mach].begin(), machine_schedule[mach].end());

        // 更新工件进度和完成时间
        job_progress[job]++;
        job_finish_time[job] = start_time + duration;
    }

    // 找到最大完成时间
    int max_time = 0;
    for (int i = 0; i < n; i++)
    {
        max_time = max(max_time, job_finish_time[i]);
    }

    // 输出结果
    cout << max_time << endl;

    return 0;
}